


#ifndef GEOMETRY_UTILS_H
#define GEOMETRY_UTILS_H

#include "Vec4.h"
#include "Matrix4.h"
#include "Aabb.h"
#include "HitData.h"
#include "Texture.h"

// STL includes
#include <string>
#include <cstring>
#include <iostream>
using std::string;

#include <vector>
using std::vector;

#include <set>
using std::set;

#include <map>
using std::map;

#include <queue>
using std::queue;

#include <math.h>
#include <cmath>
#include <stdio.h>


using namespace std;


struct GeometryUtils
{		
	
	// Point-to-line-segment
	static Vec4 closestPointOnLineSegment( const Vec4& X, const Vec4& a, const Vec4& b );
	static float pointToLineSegment( const Vec4& X, const Vec4& a, const Vec4& b, Vec4& Xp );
	
	// Point-to-triangle
	static Vec4 getClosestPointOnTriangle(const Vec4& P, const Vec4& A, const Vec4& B, const Vec4& C);
	static float vertexTriangleDistance(const Vec4& P, const Vec4& A, const Vec4& B, const Vec4& C);
	
	// Akenine-Möller triangle-box overlap test
	static int triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float triverts[3][3]);
	
	/*
	 Uses the following nice formula of Bridson for the barycoordinates (w0, w1, w2) of the point
	 obtained by projecting a point p into the plane of the triangle with vertices (x0, x1, x2):
	 
	 |x10.x10  x10.x20| |w1| = |x10.(p-x0)|
	 |x10.x20  x20.x20| |w2| = |x20.(p-x0)|
	 
	 where x10 = x1 - x0, etc.
	 The projected point is then given by p = w0 x0 + w1 x1 + w2 x2.
	 */
	static void getProjectedBarycoords(const Vec4& p, const Vec4& X0, const Vec4& X1, const Vec4& X2, float* w);
	
	static void computePlaneEquation(Vec4& normalInOut, const Vec4& pointOnPlane);
	
};


// Contains adjacency information for each vertex of a mesh
struct VertexNeighbourhood
{
	VertexNeighbourhood(int index) : m_latticeIndex(index) { }
	
	int m_latticeIndex;
	
	// Indices of vertex neighbours
	vector<int> m_neighbouringVertices;
	
	// Indices of triangles containing this vertex
	vector<int> m_parentTriangles;
	
	// Add triangle with given array index and vertex indices
	void addTriangle(int triangleIndex, int a, int b, int c)
	{
		vector<int>::iterator iter = find(m_parentTriangles.begin(), m_parentTriangles.end(), triangleIndex);
		if (iter == m_parentTriangles.end()) 
		{
			m_parentTriangles.push_back(triangleIndex);
			_addVertex(a);
			_addVertex(b);
			_addVertex(c);
		}
	}
	
private:
	
	void _addVertex(int vertexIndex)
	{
		vector<int>::iterator iter = find(m_neighbouringVertices.begin(), m_neighbouringVertices.end(), vertexIndex);
		if (iter == m_neighbouringVertices.end()) 
		{
			m_neighbouringVertices.push_back(vertexIndex);
		}
	}
	
};


#endif //GEOMETRY_UTILS_H



